
	/***********************************************************************************************

		@API
		Factory: Error
			e			jsl.Error				()
			e			jsl.Error				(msg, cause*)
			e			jsl.Error				(msg, params*, cause*)

		Methods:
      e   	message      		(msg*, params*..)
      e			cause        		(cause*)

			e			script					(name*)
      e   	trace           (cx, args*)
      st    stackTrace   		()
      e   	clearStackTrace	()

		Overriding:
			s			toString				(small*)

	************************************************************************************************/

	//-------------------------------------------------------------------------------
	jsl.Error = function(p1, p2, p3) {
		try {
			var isA, er, n, m, c

			isA = jsl.isArray(p2)//!
			if(arguments.length > (isA ? 3 : 2)) 			throw jsl.ParamError()
			if(arguments.length 			&& p1 == null)	throw jsl.ParamError("NullValue:msg")
			if(arguments.length >= 2	&& p2 == null)	throw jsl.ParamError("NullValue:" + (isA ? "params" : "cause"))
			if(arguments.length == 3 	&& p3 == null)	throw jsl.ParamError("NullValue:cause")
			if(isA && jsl.isError(p1))								throw jsl.ParamError("BadType:msg:!jsl.Error")
			//!

			//1-jsl.Error instance
			if(p1 && p1 instanceof jsl.Error) {
				er = p1
				if(arguments.length === 2) 	er.cause(p2)
			}

			//2-jsl.Error creation
			else {

				if(p1 instanceof Error) {
					c 	= jsl.__go[p1.name] && jsl[p1.name] || jsl.Error
					er	= new c
					m 	= p1.message || p1.description || ""
				}
				else {
					er 	=	this instanceof jsl.Error && !this.__created ? this : new jsl.Error
					c		= jsl.Error
					m 	= p1 + ""
					er.__created = true
				}

				er.constructor = c
				n = arguments.length
				if(n)
					if(n === 1)							er.message(m)
					else if(n === 2 && isA)	er.message(m, p2)
					else if(isA)						er.message(m, p2).cause(p3)
					else if(n === 2)				er.message(m).cause(p2)
			}

			//@sys: Firefox console - from the console a liquid error is displayed in a
			//												bad form: "Error: function [message] converted into a string"
			er.message.toString = function() { return er + "" }
    	return er
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.__errs.Error								= true
	jsl.Error.__augmented						= true
	jsl.Error.__name 								= "jsl.Error"
  jsl.Error.__native							= { __name: true, __augmented: true }
	//-------------------------------------------------------------------------------
	jsl.Error.prototype 						= jsl.Object()
	jsl.Error.prototype.__native 		= jsl.Object.clone(jsl.Object.__native)
	jsl.Error.prototype.__name 			= "jsl.Error"
	jsl.Error.prototype.__augmented	= true
	jsl.Error.prototype.__message		= null
	jsl.Error.prototype.__cause 		= null
	jsl.Error.prototype.__script 		= null
	jsl.Error.prototype.__st		 		= null
	//-------------------------------------------------------------------------------
	jsl.Error.prototype.message = function(msg, params) {
  	try {
			var id, ps, m, a, l, v//!
			if(arguments.length && msg == null)	throw jsl.ParamError("NullValue:msg")//!

			if(arguments.length) {

				//the message can be empty to avoid recursion error
				m 	= msg + ""
				id 	= m.match(/^[^:]*/)[0]

				if(id === "default" && !this.__dmessage)	throw jsl.ParamError("BadValue:msg(id):id != 'default'")

				if(arguments.length === 1) {
					ps = m.split(":").slice(1)
					for(a = 0, l = ps.length; a < l; a++)
						ps[a] = ps[a].replace(/^\s*|\s*$/g, "")
				}
				else {
					ps = []
					for(a = 1, l = arguments.length; a < l; a++)
						if(arguments[a] instanceof Array) ps = ps.concat(arguments[a])
						else ps.push(arguments[a])
				}

				//1-default  message
				//2-id message
				//3-id message without error namespace
				//4-inline message with marker and explicit parameters
				//5-inline message with explicit parameters
				//6-inline message
				try {
					if(id === "default")																		m = jsl.message(this.__dmessage, ps)
					else if(jsl.__msgs[id])																	m = jsl.message(id, ps)
					else if(jsl.__msgs["e." + id])													m = jsl.message("e." + id, ps)
					else if(arguments.length === 2 && m.charAt(0) === "!")	m = jsl.message(m.slice(1), ps)
					else if(arguments.length === 2)													m = jsl.message(m, ps)
					else if(m.charAt(0) === "!")														m = m.slice(1)
				}
				catch(e) 	{
					throw jsl.ParamError("BadArrayLength:params")
				}

				this.__message = m
	  		v = this
			}

			else if(this instanceof jsl.Error)
				v = this.__message || this.__dmessage || ""

			else
				v = this.message || this.description || ""

			return v
  	}
  	catch(e) {
  		jsl.throwError(e, this, arguments)
  	}
  }
	//-------------------------------------------------------------------------------
 	jsl.Error.prototype.cause = function(cause) {
  	try {
  		var next, v

  		//!
  		if(arguments.length > 1)								throw jsl.ParamError()
			if(arguments.length && cause == null)		throw jsl.ParamError("NullValue:cause")
			if(arguments.length && this === cause)	throw jsl.ParamError("CircularReference:cause")//!

			if(arguments.length) {//!
				next = jsl.Error(cause).cause()

				while(next) {
					if(next === this)	throw jsl.ParamError("CircularReference:cause")
					next = next.cause()
				}//!

				this.__cause = jsl.Error(cause)
	  		v = this
			}
			else
      	v = this.__cause || null

      return v
  	}
  	catch(e) {
  		jsl.throwError(e, this, arguments)
  	}
  }
	//-------------------------------------------------------------------------------
 	jsl.Error.prototype.script = function(name) {
  	try {
  		var v//!
  		if(arguments.length > 1) 	throw jsl.ParamError()
  		if(arguments.length)			jsl.validate(name, "s+", "name")//!

			if(arguments.length) {
				this.__script = name + ""
				v = this
			}
			else
      	v = this.__script || null

      return v
  	}
  	catch(e) {
  		jsl.throwError(e, this, arguments)
  	}
  }
 	//-------------------------------------------------------------------------------
	jsl.Error.prototype.trace = function(cx, args) {
		try {
			var cname, fname, context

			//1-String context
			//-----------------------------------------

			//cx can be a primitive string.
			if(typeof cx === "string") {
				//!
				if(arguments.length > 2)			throw jsl.ParamError()
				if(!cx.length)								throw jsl.ParamError("EmptyString:cx")
				if(arguments.length === 2)
					if(!jsl.isArrayLike(args))	throw jsl.ParamError("BadType:args:Array-like")//!

				context = cx
			}
			//2-Object context
			//-----------------------------------------
			else {//!
				if(arguments.length !== 2)	throw jsl.ParamError()

				jsl.validate(cx						, "o"	, "cx")
				jsl.validate(args					, "al", "args")
				jsl.validate(args.callee	, "f", "args.callee")//!

				cname = cx === jsl.__go ? "" : jsl.Object.oid(cx) || jsl.__mlng_object_name(cx)

				for(var id in cx)
					if(cx[id] === args.callee) {
						fname = id
						break
					}

				if(!fname)
					fname = jsl.Object.oid(args.callee) || jsl.__mlng_function_name(args.callee)

				fname		= fname.indexOf(".") !== -1 ? fname.slice(fname.lastIndexOf(".") + 1) : fname
				context = cname + (cname ? "." : "") + fname
			}

			//StackTrace building
			//-----------------------------------------
			if(!this.__st)
				this.__st = []

			this.__st.push({
											obj: 			typeof cx === "string" ? null 										: cx,
											method:		args && jsl.isFunction(args.callee) ? args.callee : null,
											context: 	context,
											params: 	args && args.length ? Array.prototype.slice.call(args) : []
									 	})

			return this
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.Error.prototype.stackTrace = function() {
    try {
      var trace, len
      //!
      if(arguments.length) throw jsl.ParamError()//!

			len	= this.__st ? this.__st.length : 0

      for(var a = 0, st = []; a < len; a++) {

			  trace = this.__st[a]

			  st.push({
									obj:			trace.obj							,
									method:		trace.method					,
                  context: 	trace.context       	,
                  params:		trace.params.slice()
                })
      }

      return st
    }
    catch(e) {
      jsl.throwError(e, this, arguments)
    }
  }
 	//-------------------------------------------------------------------------------
 	jsl.Error.prototype.clearStackTrace = function() {
  	try {//!
  		if(arguments.length)	throw jsl.ParamError()//!

			delete this.__st
			return this
  	}
  	catch(e) {
  		jsl.throwError(e, this, arguments)
  	}
  }
	//-------------------------------------------------------------------------------
	jsl.Error.prototype.toString = function(small) {
		try {
			var msg, s, st, line, ch, cause, params, value, context, len, v
			//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(small, "b", "small")//!

			len			= 110
			msg			= jsl.Error.message(this).replace(/^\s+|\s+$/g, "")
			st 			= jsl.Error.stackTrace(this)
			s				= jsl.__mlng_object_name(this) + (msg ? ": " + msg : "")

			if(!small) {

				if(this.__script)
					s += "\n  at script " + this.__script

				for(var a = 0; a < st.length; a++) {

					params = st[a].params

					if(params.length) {

						context	= st[a].context + "("

						for(var b = 0; b < params.length; b++) {

							//1-error
							if(jsl.isError(params[b])) value = jsl.__mlng_object_name(params[b])

							//2-string
							else if(jsl.isString(params[b])) 	{
								value = "\"" + params[b] + "\""
								//long string parameters shadow the nexts in the stacktrace
								value = value.length > 67 ? value.slice(0, 66) + "..\"" : value
							}

							//3-array
							else if(jsl.isArray(params[b]))	{

								value = "[ "

								for(var c = 0; c < params[b].length; c++) {

									v = params[b][c]

									if(jsl.isFunction(params[b][c]))		value += jsl.__mlng_object_name(v) + "()"
									else if(jsl.isError(params[b][c]))	value += jsl.__mlng_object_name(v)
									else if(jsl.isString(params[b][c]))	value += "\"" + (v.length > 15 ? v.slice(0, 15) + ".." : v) + "\""
									else if(jsl.isArray(params[b][c]))	value += "[" + v.length + "]"
									else if(jsl.isObject(params[b][c]))	value += "{..}"
									else																value += (v + "").length > 15 ? (v + "").slice(0, 15) + ".." : v + ""

									if(value.length > len) 				break
									if(c < params[b].length - 1)	value += ", "
								}

								value += " ]"
							}
							//4-regexp
							else if(jsl.isRegExp(params[b]))	value = params[b] + ""

							//5-function
							else if(jsl.isFunction(params[b]))	value = jsl.__mlng_object_name(params[b]) + "()"

							//6-object
							else if(jsl.isObject(params[b]))	{

								value = "{ "

								jsl.Object.walk(params[b], function(v, id) {

									if(id.charAt(0) !== "_") {
										value += id + ": "

										if(jsl.isFunction(v))			value += jsl.__mlng_object_name(v) + "()"
										else if(jsl.isError(v))		value += jsl.__mlng_object_name(v)
										else if(jsl.isString(v))	value += "\"" + (v.length > 15 ? v.slice(0, 15) + ".." : v) + "\""
										else if(jsl.isArray(v))		value += "[" + v.length + "]"
										else if(jsl.isObject(v))	value += "{..}"
										else											value += (v + "").length > 15 ? (v + "").slice(0, 15) + ".." : v + ""

										value += ", "
									}

									return value.length > len ? true : undefined
								})

								value = value === "{ " ? "{}" : value.slice(0, -2) + " }"
							}

							//7-other
							else	value = params[b] + ""

		          context += value.replace(/\n\r|\r\n|\n|\r/g, "\\n") + (b < params.length - 1 ? ", " : ")")

							if(context.length > len) {
								context = context.slice(0, len) + "..)"
								break
							}
						}
						s += "\n  at " + context.replace(/\n\r|\r\n|\n|\r/g, "\\n")
					}
					else
						s += "\n  at " + (st[a].context.match(/\)\s*$/) || st[a].context.match(/^script:/) ? st[a].context : st[a].context +  "()")
				}

				cause = jsl.Error.cause(this)
				if(cause) s += "\n\nCaused By\n" + cause
			}

			return s
		}
		catch(e) {
			return "jsl.Error(\"" + this.message() + "\").toString() on error: " + (e.__augmented ? e.message() : e)
		}
	}
	//Error init
	//-------------------------------------------------------------------------------
	;(function() {
		var prt, Err

		Err = jsl.Error
		prt = Err.prototype

		for(var id in prt) {

			Err.__native[id] = true
			prt.__native[id] = true

			if(typeof prt[id] === "function" && !prt[id].__name && id !== "toString") {

				Err[id] = function(obj) {
					try {//!
						if(!arguments.length)	throw jsl.ParamError()
						if(obj == null)				throw jsl.ParamError("NullValue:obj")//!

						return arguments.callee.__f.apply(obj, Array.prototype.slice.call(arguments, 1))
					}
					catch(e) {
						jsl.throwError(e, this, arguments)
					}
				}

				Err[id].__name	= prt[id].__name = id
				Err[id].__f			= prt[id]
			}
		}
	})()
